package cc.sunni.sell.aspect;

import cc.sunni.sell.constant.CookieConstant;
import cc.sunni.sell.constant.RedisConstant;
import cc.sunni.sell.entity.SellerInfo;
import cc.sunni.sell.exception.RRException;
import cc.sunni.sell.service.SellerInfoService;
import cc.sunni.sell.utils.CookieUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * 登录状态AOP
 * @author jl
 * @since 2021/1/21 19:22
 */
@Aspect
@Component
@Slf4j
public class SellerAuthorizeAspect extends HandlerInterceptorAdapter {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SellerInfoService sellerInfoService;

    private static final ThreadLocal<SellerInfo> THREAD_LOCAL = new ThreadLocal<>();

    /**
     * 定义切点
     * 包含controller包中以Seller开头的类
     * 并排除指定的controllers
     */
    @Pointcut("execution(public * cc.sunni.sell.controller.Seller*.*(..))" +
    "&& !execution(public * cc.sunni.sell.controller.SellerUserController.*(..))")
    public void verify() {}

    @Before("verify()")
    public void doVerify() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

        // 查询cookie
        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
        if (cookie == null) {
            log.warn("【登录校验】Cookie中查不到token");
            throw new RRException("请先登录");
        }

        // 查询redis
        String openId = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue()));
        if (StringUtils.isEmpty(openId)) {
            log.warn("【登录校验】Redis中查不到token");
            throw new RRException("登录状态已过期,请重新登录");
        }

        SellerInfo sellerInfo = sellerInfoService.getOne(new LambdaQueryWrapper<SellerInfo>().eq(SellerInfo::getOpenid, openId));
        //用户信息存放到线程局部变量ThreadLocal,可以在Controller、Service中取出
        THREAD_LOCAL.set(sellerInfo);
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空线程局部变量.因为使用的是tomcat的线程池,线程不会结束,也就不会自动释放局部变量.
        THREAD_LOCAL.remove();
    }

    public static SellerInfo getUserInfo() {
        return THREAD_LOCAL.get();
    }
}
